package com.itheima.demo1;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * 需求
 *  某小型商城系统的订单信息在素材下的orders.xml文件中，现在要求把xml中的订单信息，封装成一个一个的订单对象，
 *  将订单对象保存到ArrayList集合中。
 * **具体功能点要求**
 * 1)    定义订单类Order，创 建ArrayList集合，用于存储订单Order对象 （解析XML 4分，封装成对象2分）
 * 2）   请使用Stream流找出今天之前的订单，并遍历输出。（3分）
 * 3)   请使用Stream流找出集合中价格最贵的订流单，把这个订单的详细信息打印出来。（3分）
 * 4)   请使用Stream流遍历集合中的每个订单，要求按照价格降序输出每个订单的详情。（3分）
 *
 * 时间：2025年9月16日18:46:05
 *      昨天早上九点多从张家港出发深圳，终于在今天的早上八点半多到了深圳，这也是第三次来深圳，抛却任何其他的想法念头，
 *      抓住所有的时间和精力，存款和自己的耐心父母朋友的耐心，对象的关注等等一切都最多撑到明年大年初七，
 *      就要彻底包装为三年经验的简历去面试，拿到1.3w左右的offer。枯燥乏味，压力焦虑，冷嘲热讽，都是为过去三年的自己埋单。
 *      视频课程学习路线：Java入门基础，即将结束
 *      八百万播放量的JavaWeb，43h，去年学过一遍，加快速度
 *      微服务黑马商城，41h，还没做过微服务，好好敲项目，项目为主，后面背八股文才好理解
 *      Redis的黑马点评，43h，项目为主，乌拉古说Redis和MySQL需要多看
 *      苍穹外卖，38h，去年敲过一遍，有部分内容受限于基础没打好，学的懵懵懂懂，有空快速过一遍，方便写简历
 *      然后是其他：消息队列 RabbitMQ，7h   消息队列 RocketMQ，20h
 *      八股文：语雀为主
 *      MySQL，30h
 *      考虑是否看：jvm，35h       分布式任务调度Elastic-Job，3.5h
 *
 *
 * 最后一集，也就是第200集正式启动，3h。视频开头是2023.6.20.15.48。然后衔接了磊哥其他的线下上课录屏，2023.5.21.10.06
 * 看demo6的MyLinkedList.java更改时间为2025.9.19 12：24，那么大概就是这天把视频全部看完的，也就是说花了三天看了个三小时的视频。。。
 * 服了自己了
 *
 */
/*
 *          Stream提供的常用中间方法                                 说明
 *  Stream<T> filter(Predicate<? super T> predicate)            用于对流中的数据进行过滤。
 *  Stream<T>sorted()                                           对元素进行升序排序
 *  Stream<T>sorted(Comparator<? super T> comparator)           按照指定规则排序
 *  Stream<T> limit (long maxSize)                              获取前几个元素
 *  Stream<T> skip(long n)                                      跳过前几个元素
 *  Stream<T> distinct()                                        去除流中重复的元素。
 *  <R>Stream<R>map(Function<? super T,? extends R>mapper)      对元素进行加工，并返回对应的新流
 *  static <T> Stream<T> concat(Stream a, Stream b)             合并a和b两个流为一个流
 *
 *
 * 问题：我要自定义排序规则的时候，用的是double类型的怎么办，就像今天这个案例一样结果是错误的
 *      要用Double的compare方法
 *
 * Stream提供的常用终结方法
 * void forEach(Consumer action)                    对此流运算后的元素执行遍历
 * long count()                                     统计此流运算后的元素个数
 * Optional<T>max(Comparator<? super T>comparator)  获取此流运算后的最大值元素
 * Optional<T>min(Comparator<? super T>comparator)  获取此流运算后的最小值元素
 *
 * 例如：Student s = students.stream().max((o1, o2) -> Double.compare(o1.getHeight(), o2.getHeight())).get();
 *
 * 收集Stream流：就是把Stream流操作后的结果转回到集合或者数组中去返回。
 * Stream流：方便操作集合/数组的手段；   集合/数组：才是开发中的目的。
 * Collectors工具类提供了具体的收集方式
 * public static <T> Collector toList()        把元素收集到List集合中
 * public static <T> Collector toSet()         把元素收集到Set集合中
 * public static  Collector toMap(Function keyMapper , Function valueMapper)   把元素收集到Map集合中
 *
 * 疑惑：
 * 以前集合内元素指定排序规则是用下面的两种方式，但是现在是用stream流调用sort方法用lambda的方式
 *  * 方式一
 *  *      让自定义的类（如学生类）实现Comparable接口，重写里面的compareTo方法来指定比较规则。
 *  * 方式二
 *  *      public TreeSet(Comparator<? super E> comparator)
 *  *      通过调用TreeSet集合有参数构造器，可以设置Comparator对象（比较器对象，用于指定比较规则。
 */
public class Test1 {
    public static void main(String[] args) throws Exception {
        // 1、定义一个List集合存储全部订单对象
        List<Order> orders = new ArrayList<>();

        /*
         * DOM4J解析XML文件的思想，文档对象模型：(是一种自上而下式的解析思想)
         *      1.SAXReader解析器可以把要解析的xml文件加载到内存中
         *      2.使用saxReader对象把需要解析的XML文件读成一个Document对象。这个文档对象可以代表整个xml文件，通过文档对象来访问 xml里面的所有数据
         *      3.然后通过文档对象去获取文档里面的Element对象：元素对象（也叫标签对象），可以获取xml文件中的根元素对象或者子元素对象
         *      4.接着可以通过元素对象获取元素的名字，还可以拿到 “Attribute:属性”对象，也可以拿到 “子元素、文本”
         *
         *  *    Document对象的方法名：
         * Element getRootElement()                 获得根元素对象
         *
         *    Element对象提供的方法：
         * public String getName()                          得到元素名字
         * public List<Element> elements()                  得到当前元素下所有子元素
         * public List<Element> elements(String name)       得到当前元素下指定名字的子元素返回集合
         * public Element element(String name)              得到当前元素下指定名字的子元素,如果有很多名字相同的返回第一个
         * public String  attributeValue(String name)       通过属性名直接得到属性值
         * public String elementText(子元素名)               得到指定名称的子元素的文本
         * public String getText()                          得到文本
         */

        // 2、导入dom4j框架.
        SAXReader saxReader = new SAXReader();
        // 3、读取xml文件成为一个Document对象，并且用相对路径会更符合跨平台
        //用类对象提供的方法getResourceAsStream来拿orders.xml文件，磊哥说教过，但是B站的视频课是没有的。有异常直接抛出去
        Document document = saxReader.read(Test1.class.getResourceAsStream("/orders.xml"));
        // 4、提取根元素，也就是orders.xml里面的orders根元素
        Element root = document.getRootElement();

        // 5、提取一级子元素（order订单元素） 并且注意orders.xml的每个order订单元素和order对象要求的成员属性都对得上
        List<Element> orderEles = root.elements();
        //转换器来解析时间字符串
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 6、遍历每个订单元素   所以每个order订单元素就是一个order对象
        for (Element orderEle : orderEles) {
            // 7、每个订单元素是一个订单对象。
            Order order = new Order();

            //通过属性名直接得到属性值，并且拿到的是一级属性，以字符串形式返回的，所以要转换成整数
            //包装类是对基本类型的包装，把基本数据类型转换为包装类的过程就是装箱，把包装类转换为基本数据类型的过程就是拆箱
            //自动装箱都是通过包装类的 value0f()方法来实现的.自动拆箱都是通过包装类对象的 xxxValue()来实现的。
            //如:int的自动装箱都是通过 Integer.value0f()方法来实现的，Integer的自动拆箱都是通过 Integer.intValue()来实现的。
            order.setId(Integer.valueOf(orderEle.attributeValue("id")));
            //得到指定名称的子元素的文本
            order.setName(orderEle.elementText("name"));

            //这样是解析不了拿到的时间文本
            //order.setTime(LocalDateTime.parse(orderEle.elementText("time")));
            //所以要拿转换器来解析：
            order.setTime(LocalDateTime.parse(orderEle.elementText("time"), dtf));

            order.setPrice(Double.valueOf(orderEle.elementText("double")));
            // 8、把订单对象存入到集合中去
            orders.add(order);
        }
        System.out.println("---------------看一下提取一级子元素（order订单元素）orderEles列表：------------");
        System.out.println(orderEles);

        System.out.println("订单内容如下：");
        //System.out.println(orders);       //这样直接输出太丑了
        for (Order order : orders) {
            System.out.println(order);
        }

        // 9、请使用Stream流找出今天之前的订单，并遍历输出。
        System.out.println("今天之前的订单如下：");
        //用isBefore方法过滤出在今天之前时间的订单对象
        orders.stream().filter(o -> o.getTime().isBefore(LocalDateTime.now())).forEach(System.out::println);

        // 10、请使用Stream流找出集合中价格最贵的订单，把这个订单的详细信息打印出来
        System.out.println("最贵的订单如下：");
        /*
         * 问题：我要自定义排序规则的时候，用的是double类型的怎么办，就像今天这个案例一样结果是错误的
         *      要用Double的compare方法
         */
        //写个max的比较器判断价格，来找最贵的订单。对max按住ctrl键发现返回的是optional类型的对象，然后用get方法。好像没讲过
        Order order = orders.stream().max((o1, o2) -> Double.compare(o1.getPrice(), o2.getPrice())).get();
        System.out.println(order);

        // 11、请使用Stream流遍历集合中的每个订单，要求按照价格降序输出每个订单的详情。
        System.out.println("根据价格降序如下：");
        //降序：o2在前，o1在后
        orders.stream().sorted((o1, o2) -> Double.compare(o2.getPrice(), o1.getPrice())).forEach(System.out::println);
    }
}








